﻿#region MIT Licenze
//The MIT License

//Copyright (c) 2008 Sebastian Faltoni, dotnetfireball.org

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Windows;
using Fireball.Extensions;
using System.Windows.Markup;
using System.ComponentModel;

namespace Fireball.OpenXML.Word
{
    /// <summary>
    /// The cell for Table
    /// </summary>
    [ContentProperty("ChildBlocks")]
    public class TableCell : OpenXMLEntity, IFindable, IAddChild
    {
        private TableRow _OwnerRow = null;

        /// <summary>
        /// The OwnerRow of this Cell
        /// </summary>
        public TableRow OwnerRow
        {
            get
            {
                return _OwnerRow;
            }
        }

        internal void SetOwnerRow(TableRow owner)
        {
            this._OwnerRow = owner;
        }

        private BlockCollection _ChildBlocks = null;


        /// <summary>
        /// The collections for the childs block's of 
        /// this TableCell
        /// </summary>
        public BlockCollection ChildBlocks
        {
            get
            {
                return _ChildBlocks;
            }
        }

        /// <summary>
        /// The cell width
        /// </summary>
        public TableCellWidth Width
        {
            get;
            set;
        }


        /// <summary>
        /// The border's Size of this cell
        /// </summary>
        public Thickness? BorderSize
        {
            get;
            set;
        }

        /// <summary>
        /// The cell margin
        /// </summary>
        public TableCellMargin Margin
        {
            get;
            set;
        }

        public TableCellShading Shading
        {
            get;
            set;
        }

        [DefaultValue(VerticalAlignment.Top)]
        public VerticalAlignment VAlign
        {
            get;
            set;
        }

        /*/// <summary>
        /// The space between the cell borders and the
        /// content
        /// </summary>
        public BorderSpace BorderSpace
        {
            get;
            set;
        }

        /// <summary>
        /// The borders color's of this cell
        /// </summary>
        public BorderColor BorderColor
        {
            get;
            set;
        }*/


        #region BorderLeft
        private TableBorder _BorderLeft;

        public TableBorder BorderLeft
        {
            get
            {
                return _BorderLeft;
            }
            set
            {
                _BorderLeft = value;

                _BorderLeft.BorderKind = BorderKind.Left;
            }
        }

        #endregion

        #region BorderRight
        private TableBorder _BorderRight;

        public TableBorder BorderRight
        {
            get
            {
                return _BorderRight;
            }
            set
            {
                _BorderRight = value;

                _BorderRight.BorderKind = BorderKind.Right;
            }

        } 
        #endregion

        #region BorderTop
        private TableBorder _BorderTop;

        public TableBorder BorderTop
        {
            get
            {
                return _BorderTop;
            }
            set
            {
                _BorderTop = value;

                _BorderTop.BorderKind = BorderKind.Top;
            }
        } 
        #endregion

        #region BorderBottom
        private TableBorder _BorderBottom;

        public TableBorder BorderBottom
        {
            get
            {
                return _BorderBottom;
            }
            set
            {
                _BorderBottom = value;

                _BorderBottom.BorderKind = BorderKind.Bottom;
            }
        } 
        #endregion

        /// <summary>
        /// Specify the numbers of column's on with this will expand
        /// their content
        /// </summary>
        public int ColumnSpan
        {
            get;
            set;
        }

        public TableCell()
        {
            this._ChildBlocks = new BlockCollection(this);
            //Aggiungo un paragrafo perche' e' obbligatorio avere un contenuto
            // this.ChildBlocks.Add(new Paragraph());
        }

        public override System.Xml.Linq.XContainer ToXml()
        {

            var last = (this.ChildBlocks.Count == 0 ? null : this.ChildBlocks.Last());

            if (last == null || last.GetType() != typeof(Paragraph))
                this.ChildBlocks.Add(new Paragraph());

            var xCell = new XElement(NS.WM + "tc");

            var tcPr = new XElement(NS.WM + "tcPr");
            xCell.Add(tcPr);

            if (this.Width != null)
            {
                tcPr.Add(this.Width.ToXml());
            }

            if (this.ColumnSpan > 0)
            {
                tcPr.Add(new XElement(NS.WM + "gridSpan",
                    new XAttribute(NS.WM + "val", this.ColumnSpan)));
            }

            #region Borders
            XElement tcBorders = new XElement(NS.WM + "tcBorders");

            if (this.BorderTop != null)
            {
                var bt = this.BorderTop.ToXml();

                if (bt != null)
                    tcBorders.Add(bt);
            }

            if (this.BorderLeft != null)
            {
                var bl = this.BorderLeft.ToXml();

                if (bl != null)
                    tcBorders.Add(bl);
            }

            if (this.BorderBottom != null)
            {
                var bb = this.BorderBottom.ToXml();

                if (bb != null)
                    tcBorders.Add(bb);
            }


            if (this.BorderRight != null)
            {
                var br = this.BorderRight.ToXml();

                if (br != null)
                    tcBorders.Add(br);
            }

            if (tcBorders.Elements().Count() > 0)
                tcPr.Add(tcBorders);
            #endregion Borders

            if (this.Margin != null)
            {
                tcPr.Add(this.Margin.ToXml());
            }


            if (this.Shading != null)
            {
                tcPr.Add(this.Shading.ToXml());
            }

            tcPr.Add(new XElement(NS.WM + "vAlign",
                    new XAttribute(NS.WM + "val", this.VAlign.ToOffice())));



            xCell.Add((from p in this.ChildBlocks select p.ToXml()).ToArray());
            return xCell;
            //var xCell = new XElement(NS.WM + "tc",                
            //    new XElement(NS.WM + "tcPr",
            //    new XElement(NS.WM + "gridSpan",                
            //        new XAttribute(NS.WM + "val", this.ColumnSpan))),//,
            //       // GetBordersXml()),
            //    (from p in this.ChildBlocks select p.ToXml()).ToArray());
            //return xCell;
        }
        /*
        private XElement GetBordersXml()
        {
            var xBorders = new XElement(NS.WM + "tcBorders");

            if (this.BorderSize.Value.Top > 0)
                xBorders.Add(new XElement(NS.WM + "top",
                        new XAttribute(NS.WM + "val", "single"),
                        new XAttribute(NS.WM + "sz", this.BorderSize.Value.Top),
                        new XAttribute(NS.WM + "space", this.BorderSpace.Top),
                        new XAttribute(NS.WM + "color",
                           (this.BorderColor.Top == null ? "auto" : this.BorderColor.Top.ToHexFormat()))
                        ));
            else
                xBorders.Add(new XElement(NS.WM + "top",
                        new XAttribute(NS.WM + "val", "nil")));

            if (this.BorderSize.Value.Left > 0)
                xBorders.Add(new XElement(NS.WM + "left",
                        new XAttribute(NS.WM + "val", "single"),
                        new XAttribute(NS.WM + "sz", this.BorderSize.Value.Left),
                        new XAttribute(NS.WM + "space", this.BorderSpace.Left),
                        new XAttribute(NS.WM + "color",
                           (this.BorderColor.Left == null ? "auto" : this.BorderColor.Left.ToHexFormat()))
                        ));
            else
                xBorders.Add(new XElement(NS.WM + "left",
                        new XAttribute(NS.WM + "val", "nil")));

            if (this.BorderSize.Value.Bottom > 0)
                xBorders.Add(new XElement(NS.WM + "bottom",
                        new XAttribute(NS.WM + "val", "single"),
                        new XAttribute(NS.WM + "sz", this.BorderSize.Value.Bottom),
                        new XAttribute(NS.WM + "space", this.BorderSpace.Bottom),
                        new XAttribute(NS.WM + "color",
                           (this.BorderColor.Bottom == null ? "auto" : this.BorderColor.Bottom.ToHexFormat()))
                        ));
            else
                xBorders.Add(new XElement(NS.WM + "bottom",
                        new XAttribute(NS.WM + "val", "nil")));

            if (this.BorderSize.Value.Right > 0)
                xBorders.Add(new XElement(NS.WM + "right",
                        new XAttribute(NS.WM + "val", "single"),
                        new XAttribute(NS.WM + "sz", this.BorderSize.Value.Right),
                        new XAttribute(NS.WM + "space", this.BorderSpace.Right),
                        new XAttribute(NS.WM + "color",
                           (this.BorderColor.Right == null ? "auto" : this.BorderColor.Right.ToHexFormat()))
                        )
                        );
            else
                xBorders.Add(new XElement(NS.WM + "right",
                        new XAttribute(NS.WM + "val", "nil")));

            return xBorders;
        }
        */

        #region IFindable Members

        public OpenXMLEntity FindByName(string name)
        {
            foreach (var b in this.ChildBlocks)
            {
                if (b.Name == name)
                    return b;

                if (b is IFindable)
                {
                    IFindable bf = (IFindable)b;

                    var bs = bf.FindByName(name);

                    if (bs != null)
                        return bs;
                }
            }
            return null;
        }

        #endregion

        #region IAddChild Members

        public void AddChild(object value)
        {
            if (!(value is Block))
                throw new Exception("Invalid child type requested a type of Block");

            this._ChildBlocks.Add((Block)value);
        }

        public void AddText(string text)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public enum WidthType
    {
        Nil,
        Auto,
        Pct,
        Dxa
    }

    public class TableCellSize
    {
        public int Width
        {
            get;
            set;
        }

        public WidthType Type
        {
            get;
            set;
        }
    }
}
